﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Globalization;
using Enterprise.Utilities;

namespace Enterprise.Data
{
    public static class DataMapper
    {
        // Methods
        private static PropertyInfo[] GetSourceProperties(Type sourceType)
        {
            List<PropertyInfo> list = new List<PropertyInfo>();
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(sourceType))
            {
                if (descriptor.IsBrowsable)
                {
                    list.Add(sourceType.GetProperty(descriptor.Name));
                }
            }
            return list.ToArray();
        }

        private static object GetValue(MemberInfo member, object source)
        {
            if (member.MemberType == MemberTypes.Property)
            {
                return ((PropertyInfo)member).GetValue(source, null);
            }
            return ((FieldInfo)member).GetValue(source);
        }

        public static void Map(IDictionary source, object target)
        {
            Map(source, target, false, new string[0]);
        }

        public static void Map(object source, Dictionary<string, object> target)
        {
            Map(source, target, false, new string[0]);
        }

        public static void Map(object source, object target)
        {
            Map(source, target, false, new string[0]);
        }

        public static void Map(IDictionary source, object target, params string[] ignoreList)
        {
            Map(source, target, false, ignoreList);
        }

        public static void Map(object source, Dictionary<string, object> target, params string[] ignoreList)
        {
            Map(source, target, false, ignoreList);
        }

        public static void Map(object source, object target, params string[] ignoreList)
        {
            Map(source, target, false, ignoreList);
        }

        public static void Map(object source, object target, DataMap map)
        {
            Map(source, target, map, false);
        }

        public static void Map(IDictionary source, object target, bool suppressExceptions, params string[] ignoreList)
        {
            List<string> list = new List<string>(ignoreList);
            foreach (string str in source.Keys)
            {
                if (!list.Contains(str))
                {
                    try
                    {
                        SetPropertyValue(target, str, source[str]);
                        continue;
                    }
                    catch (Exception exception)
                    {
                        if (!suppressExceptions)
                        {
                            throw;
                        }
                        continue;
                    }
                }
            }
        }

        public static void Map(object source, Dictionary<string, object> target, bool suppressExceptions, params string[] ignoreList)
        {
            List<string> list = new List<string>(ignoreList);
            foreach (PropertyInfo info in GetSourceProperties(source.GetType()))
            {
                string name = info.Name;
                if (!list.Contains(name))
                {
                    try
                    {
                        target.Add(name, info.GetValue(source, null));
                    }
                    catch (Exception exception)
                    {
                        if (!suppressExceptions)
                        {
                            throw;
                        }
                    }
                }
            }
        }

        public static void Map(object source, object target, DataMap map, bool suppressExceptions)
        {
            foreach (DataMap.MemberMapping mapping in map.GetMap())
            {
                try
                {
                    object obj2 = GetValue(mapping.FromMember, source);
                    SetValue(target, mapping.ToMember, obj2);
                    continue;
                }
                catch (Exception exception)
                {
                    if (!suppressExceptions)
                    {
                        throw;
                    }
                    continue;
                }
            }
        }

        public static void Map(object source, object target, bool suppressExceptions, params string[] ignoreList)
        {
            List<string> list = new List<string>(ignoreList);
            foreach (PropertyInfo info in GetSourceProperties(source.GetType()))
            {
                string name = info.Name;
                if (!list.Contains(name))
                {
                    try
                    {
                        SetPropertyValue(target, name, info.GetValue(source, null));
                    }
                    catch (Exception exception)
                    {
                        if (!suppressExceptions)
                        {
                            throw;
                        }
                    }
                }
            }
        }

        public static void SetFieldValue(object target, string fieldName, object value)
        {
            FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            SetValue(target, field, value);
        }

        public static void SetPropertyValue(object target, string propertyName, object value)
        {
            PropertyInfo property = target.GetType().GetProperty(propertyName, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
            SetValue(target, property, value);
        }

        public static void SetValue(object target, MemberInfo memberInfo, object value)
        {
            if (value != null)
            {
                Type fieldType;
                object obj2;
                if (memberInfo.MemberType == MemberTypes.Property)
                {
                    PropertyInfo info = (PropertyInfo)memberInfo;
                    fieldType = info.PropertyType;
                    obj2 = info.GetValue(target, null);
                }
                else
                {
                    FieldInfo info2 = (FieldInfo)memberInfo;
                    fieldType = info2.FieldType;
                    obj2 = info2.GetValue(target);
                }
                Type propertyType = ReflectionHelper.GetPropertyType(value.GetType());
                value = ReflectionHelper.CoerceValue(fieldType, propertyType, obj2, value);
            }
            if (memberInfo.MemberType == MemberTypes.Property)
            {
                ((PropertyInfo)memberInfo).SetValue(target, value, null);
            }
            else
            {
                ((FieldInfo)memberInfo).SetValue(target, value);
            }
        }
    }


}
